{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "NumPy UltraQuick Tutorial",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "metadata": {
        "id": "JuGzpxT_Z1EU",
        "colab_type": "code",
        "cellView": "form",
        "colab": {}
      },
      "source": [
        "#@title Copyright 2020 Google LLC. Double-click here for license information.\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "T4r2z30vJSbA",
        "colab_type": "text"
      },
      "source": [
        "# NumPy UltraQuick Tutorial\n",
        "\n",
        "NumPy is a Python library for creating and manipulating vectors and matrices. This Colab is not an exhaustive tutorial on NumPy.  Rather, this Colab teaches you just enough to use NumPy in the Colab exercises of Machine Learning Crash Course. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vO47lN3aDOAv",
        "colab_type": "text"
      },
      "source": [
        "## About Colabs\n",
        "\n",
        "Machine Learning Crash Course uses Colaboratories (**Colabs**) for all programming exercises. Colab is Google's implementation of [Jupyter Notebook](https://jupyter.org/). Like all Jupyter Notebooks, a Colab consists of two kinds of components:\n",
        "\n",
        "  * **Text cells**, which contain explanations. You are currently reading a text cell.\n",
        "  * **Code cells**, which contain Python code for you to run. Code cells have a light gray background.\n",
        "\n",
        "You *read* the text cells and *run* the code cells. \n",
        "\n",
        "\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SQ-pvdPymocS",
        "colab_type": "text"
      },
      "source": [
        "### Running code cells\n",
        "\n",
        "You must run code cells in order. In other words, you may only run a code cell once all the code cells preceding it have already been run. \n",
        "\n",
        "To run a code cell:\n",
        "\n",
        "  1. Place the cursor anywhere inside the [ ] area at the top left of a code cell. The area inside the [ ] will display an arrow.\n",
        "  2. Click the arrow.\n",
        "\n",
        "Alternatively, you may invoke **Runtime->Run all**. Note, though, that some of the code cells will fail because not all the coding is complete. (You'll complete the coding as part of the exercise.)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v9GhD7Fsmoqw",
        "colab_type": "text"
      },
      "source": [
        "### If you see errors...\n",
        "\n",
        "The most common reasons for seeing code cell errors are as follows:\n",
        "\n",
        "  * You didn't run *all* of the code cells preceding the current code cell.\n",
        "  * If the code cell is labeled as a **Task**, then:\n",
        "    *  You haven't yet written the code that implements the task.\n",
        "    *  You did write the code, but the code contained errors."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ll9RWewwFwX6",
        "colab_type": "text"
      },
      "source": [
        "## Import NumPy module\n",
        "\n",
        "Run the following code cell to import the NumPy module:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "guvPzSWYJGZ4",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import numpy as np "
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7cT9fXS_JUpa",
        "colab_type": "text"
      },
      "source": [
        "## Populate arrays with specific numbers\n",
        "\n",
        "Call `np.array` to create a NumPy matrix with your own hand-picked values. For example, the following call to `np.array` creates an 8-element vector:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XxJR5xKpJbB3",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "one_dimensional_array = np.array([1.2, 2.4, 3.5, 4.7, 6.1, 7.2, 8.3, 9.5])\n",
        "print(one_dimensional_array)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RKywqhLTbR1M",
        "colab_type": "text"
      },
      "source": [
        "You can also use `np.array` to create a two-dimensional matrix. To create a two-dimensional matrix, specify an extra layer of square brackets. For example, the following call creates a 3x2 matrix:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_veGj18eMCDu",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "two_dimensional_array = np.array([[6, 5], [11, 7], [4, 8]])\n",
        "print(two_dimensional_array)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0ED7eug9CvGR",
        "colab_type": "text"
      },
      "source": [
        "To populate a matrix with all zeroes, call `np.zeros`. To populate a matrix with all ones, call `np.ones`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gEy_pdBoROu3",
        "colab_type": "text"
      },
      "source": [
        "## Populate arrays with sequences of numbers\n",
        "\n",
        "You can populate an array with a sequence of numbers:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "CjHfYWhdQYtO",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "sequence_of_integers = np.arange(5, 12)\n",
        "print(sequence_of_integers)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1x3OoWrPWn8S",
        "colab_type": "text"
      },
      "source": [
        "Notice that `np.arange` generates a sequence that includes the lower bound (5) but not the upper bound (12). "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aiqqxDBINAOY",
        "colab_type": "text"
      },
      "source": [
        "## Populate arrays with random numbers\n",
        "\n",
        "NumPy provides various functions to populate matrices with random numbers across certain ranges. For example, `np.random.randint` generates random integers between a low and high value. The following call populates a 6-element vector with random integers between 50 and 100. \n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "tG8ao9CsNqw8",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "random_integers_between_50_and_100 = np.random.randint(low=50, high=101, size=(6))\n",
        "print(random_integers_between_50_and_100)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BSU7lMUcgRm3",
        "colab_type": "text"
      },
      "source": [
        "Note that the highest generated integer `np.random.randint` is one less than the `high` argument."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lQF6-Eg0ksqE",
        "colab_type": "text"
      },
      "source": [
        "To create random floating-point values between 0.0 and 1.0, call `np.random.random`. For example:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "6Ny0eXZPk5Ax",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "random_floats_between_0_and_1 = np.random.random([6])\n",
        "print(random_floats_between_0_and_1) "
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eXOdSjRlSEf6",
        "colab_type": "text"
      },
      "source": [
        "## Mathematical Operations on NumPy Operands\n",
        "\n",
        "If you want to add or subtract two vectors or matrices, linear algebra requires that the two operands have the same dimensions. Furthermore, if you want to multiply two vectors or matrices, linear algebra imposes strict rules on the dimensional compatibility of operands. Fortunately, NumPy uses a trick called [**broadcasting**](https://developers.google.com/machine-learning/glossary/#broadcasting) to virtually expand the smaller operand to dimensions compatible for linear algebra. For example, the following operation uses broadcasting to add 2.0 to the value of every item in the vector created in the previous code cell:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "J5E5S0wjRvQr",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "random_floats_between_2_and_3 = random_floats_between_0_and_1 + 2.0\n",
        "print(random_floats_between_2_and_3)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x6K_poVDPpAg",
        "colab_type": "text"
      },
      "source": [
        "The following operation also relies on broadcasting to multiply each cell in a vector by 3:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "tYjvXmvFPoPB",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "random_integers_between_150_and_300 = random_integers_between_50_and_100 * 3\n",
        "print(random_integers_between_150_and_300)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hfYVa8iQTaUL",
        "colab_type": "text"
      },
      "source": [
        "## Task 1: Create a Linear Dataset\n",
        "\n",
        "Your goal is to create a simple dataset consisting of a single feature and a label as follows:\n",
        "\n",
        "1. Assign a sequence of integers from 6 to 20 (inclusive) to a NumPy array named `feature`.\n",
        "2. Assign 15 values to a NumPy array named `label` such that:\n",
        "\n",
        "```\n",
        "   label = (3)(feature) + 4\n",
        "```\n",
        "For example, the first value for `label` should be:\n",
        "\n",
        "```\n",
        "  label = (3)(6) + 4 = 22\n",
        " ```"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "qK9UF2rUc3Y_",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "feature = ? # write your code here\n",
        "print(feature)\n",
        "label = ?   # write your code here\n",
        "print(label)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "KjtIAYvMTPGl",
        "colab_type": "code",
        "cellView": "form",
        "colab": {}
      },
      "source": [
        "#@title Double-click to see a possible solution to Task 1.\n",
        "feature = np.arange(6, 21)\n",
        "print(feature)\n",
        "label = (feature * 3) + 4\n",
        "print(label)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RNsjGYRj87PB",
        "colab_type": "text"
      },
      "source": [
        "## Task 2: Add Some Noise to the Dataset\n",
        "\n",
        "To make your dataset a little more realistic, insert a little random noise into each element of the `label` array you already created. To be more precise, modify each value assigned to `label` by adding a *different* random floating-point value between -2 and +2. \n",
        "\n",
        "Don't rely on broadcasting. Instead, create a `noise` array having the same dimension as `label`."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HF-flFfs9r0q",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "noise = ?    # write your code here\n",
        "print(noise)\n",
        "label = ?    # write your code here\n",
        "print(label)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "7chgYKrC93np",
        "colab_type": "code",
        "cellView": "form",
        "colab": {}
      },
      "source": [
        "#@title Double-click to see a possible solution to Task 2.\n",
        "\n",
        "noise = (np.random.random([15]) * 4) - 2\n",
        "print(noise)\n",
        "label = label + noise \n",
        "print(label)"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}